package dmt16.TelemetrySuit.Communication.PacketTypes
{
	import dmt16.TelemetrySuit.Communication.PacketReceivedEvent;
	
	import flash.errors.IOError;
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.utils.ByteArray;
	import flash.utils.Endian;
	
	public final class PacketReader extends EventDispatcher
	{
		private var _buffer:ByteArray;
		private var _p:Number=0;
		private var _dataEnd:Number=0;
		
		public static var instance:PacketReader;
		
		{
			instance=new PacketReader();			
		}
		
		public function PacketReader(){
			_buffer=new ByteArray();
			_buffer.length=2048;
			_buffer.endian=Endian.LITTLE_ENDIAN;
		}
		
		private function _makePacket(type:int,content:ByteArray,checksum:int):IPacket
		{
			var packet:IPacket;
			switch(type){
				case PacketType.DATA_MESSAGE:
					packet=new DataMessage(content,checksum);
					break;
				case PacketType.DVC_CONFIG_STATUS:
					packet=new DeviceConfigurationStatus(content,checksum);
					break;
				case PacketType.DVC_DISCONNECT:
					packet=new DisconnectRequest(content,checksum);
					break;
				case PacketType.DVC_INIT:
					packet=new InitialisationRequest(content,checksum);
					break;
				case PacketType.MSG_ACK:
					packet=new MessageAcknowledge(content,checksum);
					break;
				default:
					trace("ERROR: Unknown Packet Type: "+type.toString(16));
					break;
			}
			return packet;
		}
		
		public static function addEventListener(type:String,listener:Function,useCapture:Boolean=false,priority:int=0,useWeakReference:Boolean=false):void{
			instance.addEventListener(type,listener,useCapture,priority,useWeakReference);
		}
		
		public static function parseData(data:ByteArray):void
		{
			instance._parseData(data);
		}
		
		private function _parseData(data:ByteArray):void
		{
			var i:Number;
			
			if(data!=null){
				if(data.length>_buffer.bytesAvailable){		//Check there is space for the data
					throw new IOError("Error decoding data packets, Buffer Overflow");
					return;
				}
				_buffer.position=_dataEnd;
				_buffer.writeBytes(data);
				_dataEnd+=data.length;
			}

			_p=0;
			
			while((_buffer[_p]!=0x01)&&(++_p<_dataEnd)){}	//Find the start of a packet (0x01)
			
			if(_p==_buffer.length){	//Check if no packets are found
				throw new IOError("Error decoding data packets, No Start Packet Found");
				return;
			}
			
			var packetStart:int=_p;
			var type:int=-1;
			var len:int=-1;
			if(_p+4<_dataEnd) // enough bytes to read packet header
			{
				_buffer.position=_p+1;
				type=_buffer.readUnsignedByte(); // read type
				len=_buffer.readUnsignedShort(); // read length
				
				var D:String="";
				for(var n:int=0; n<_buffer.length; n++){
					D+=int(_buffer[n]).toString(16)+",";
				}
				if(_p+4+len+3<=_dataEnd){		// check whole packet is available
					var packetData:ByteArray=new  ByteArray();
					if(len>0){
						packetData.length=len;
						packetData.writeBytes(_buffer,_p+4,len); //read packet data
					}
					_buffer.position=_p+4+len;
					var checksum:uint=_buffer.readUnsignedShort();
					_buffer.position++;
					
					var packet:IPacket=_makePacket(type,packetData,checksum);
					var evt:PacketReceivedEvent=new PacketReceivedEvent(PacketReceivedEvent.ON_PACKET_RECEIVED);
					evt.packet=packet
					dispatchEvent(evt);
					_p=_buffer.position;
					for(i=0;i<_dataEnd-_p;i++)
						_buffer[i]=_buffer[_p+i];
					_dataEnd-=_p;
					_p=0;
					if(_dataEnd>0)
						parseData(null);
				}
				else
				{
					for(i=0;i<_dataEnd-_p;i++)
						_buffer[i]=_buffer[_p+i];
					_dataEnd-=_p;
					_p=0;
				}
			}
		}
	}
}